From: Brion Vibber Date: Thu, 9 Jun 2005 09:49:10 +0000 (+0000) Subject: Rework the user_groups system, again, into something that seems to actually X-Git-Tag: 1.5.0beta1~207 X-Git-Url: http://git.cyclocoop.org/%7D%7Cconcat%7B?a=commitdiff_plain;h=a6d47f47ffb57840625997063ce01a93d204cdc2;p=lhc%2Fweb%2Fwiklou.git Rework the user_groups system, again, into something that seems to actually more or less work for now. * user_groups ur_group is now a short string key ('sysop' etc) * groups table is gone * user_rights table is gone * Permissions for groups are for now set in $wgGroupPermissions. An in-database management system could be re-added in the future if it's really needed, but for now it's mostly just been screwing things up. * Group.php and Special:Groups are deprecated; will probably die. * User group memberships are set explicitly through addGroup and removeGroup methods instead of being re-saved on every change to the user record. Group keys are migrated from user_rights at upgrade time for older wikis. The fields in prior 1.5alpha tables were too screwed up and will need to manually have sysops re-assigned. The Makesysop extension will need some minor tweaks. --- diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 95a07fcb39..c60284ed0b 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -272,6 +272,7 @@ Various bugfixes, small features, and a few experimental things: * (bug 2309) Allow templates and template parameters in HTML attribute zone, with proper validation checks. (regression from fix for 2304) * Disallow close tags and enforce empty tags for
and
+* Changed user_groups format quite a bit. === Caveats === diff --git a/config/index.php b/config/index.php index 8d9223e30a..9600f003d0 100644 --- a/config/index.php +++ b/config/index.php @@ -565,7 +565,6 @@ if( $conf->posted && ( 0 == count( $errs ) ) ) { print "
  • Creating tables..."; dbsource( "../maintenance/tables.sql", $wgDatabase ); dbsource( "../maintenance/interwiki.sql", $wgDatabase ); - dbsource( "../maintenance/archives/patch-userlevels-defaultgroups.sql", $wgDatabase ); print " done.
  • \n"; print "
  • Initializing data..."; @@ -585,9 +584,10 @@ if( $conf->posted && ( 0 == count( $errs ) ) ) { if ( 0 == $u->idForName() ) { $u->addToDatabase(); $u->setPassword( $conf->getSysopPass() ); - $u->addRight( "sysop" ); - $u->addRight( "bureaucrat" ); $u->saveSettings(); + + $u->addGroup( "sysop" ); + $u->addGroup( "bureaucrat" ); print "
  • Created sysop account " . htmlspecialchars( $conf->SysopName ) . ".
  • \n"; diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index ffb26c194b..4e79cea986 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -671,12 +671,25 @@ $wgBlockExpiryOptions = "2 hours,1 day,3 days,1 week,2 weeks,1 month,3 months,6 $wgAutoblockExpiry = 86400; # Number of seconds before autoblock entries expire /** - * Static user groups serialized record - * To avoid database access, you can set this to a user groups record as returned - * by Special:Groups with the magic parameter showrecord=1. This will however mean - * that you won't be able to edit them at runtime. - */ -$wgStaticGroups = false; + * Permission keys given to users in each group. + * All users are implicitly in the '*' group including anonymous visitors; + * logged-in users are all implicitly in the 'user' group. These will be + * combined with the permissions of all groups that a given user is listed + * in in the user_groups table. + */ +$wgGroupPermissions = array( + '*' => array( 'read', 'createaccount' ), + 'user' => array( 'read', 'move' ), + + 'bot' => array( 'bot' ), + 'sysop' => array( 'createaccount', 'patrol', 'protect', 'delete', + 'rollback', 'block', 'editinterface' ), + 'bureaucrat' => array( 'userrights' ), + 'steward' => array( 'makesysop' ), # technically this is for an extension... + 'developer' => array( 'siteadmin' ), +); + + # Proxy scanner settings # @@ -1319,14 +1332,6 @@ $wgBrowserBlackList = array( # $wgLocaltimezone = 'CET'; $wgLocaltimezone = null; -/** - * User level management - * The number is the database id of a group you want users to be attached by - * default. A better interface should be coded [av] - */ -$wgAnonGroupId = 1; -$wgLoggedInGroupId = 2; - /** * When translating messages with wfMsg(), it is not always clear what should be diff --git a/includes/HTMLForm.php b/includes/HTMLForm.php index b15e70d253..12147d5510 100644 --- a/includes/HTMLForm.php +++ b/includes/HTMLForm.php @@ -120,26 +120,34 @@ class HTMLForm { * @param boolean $reverse If true, multiple select will hide selected elements (default false). */ function HTMLSelectGroups($selectname, $selectmsg, $selected=array(), $multiple=false, $size=6, $reverse=false) { - global $wgOut; - $groups =& Group::getAllGroups(); + $groups = User::getAllGroups(); + $out = htmlspecialchars( wfMsg( $selectmsg ) ); - $out = wfMsg($selectmsg); - $out .= '\n"; return $out; } diff --git a/includes/SpecialListusers.php b/includes/SpecialListusers.php index 28837db8c9..e30078a3c0 100644 --- a/includes/SpecialListusers.php +++ b/includes/SpecialListusers.php @@ -64,18 +64,22 @@ class ListUsersPage extends QueryPage { // form header $out = '
    ' . '' . - wfMsg( 'grouplevels-editgroup-name' ) . ''; // get all group names and IDs - $groups =& Group::getAllGroups(); + $groups = User::getAllGroups(); // we want a default empty group $out.= ''; // build the dropdown list menu using datas from the database foreach ( $groups as $group ) { - $selected = ($group->getId() == $this->requestedGroup) ? ' selected ' : '' ; - $out.= ''; + $selected = ($group == $this->requestedGroup); + $out .= wfElement( 'option', + array_merge( + array( 'value' => $group ), + $selected ? array( 'selected' => 'selected' ) : array() ), + User::getGroupName( $group ) ); } $out .= ' '; @@ -89,24 +93,16 @@ class ListUsersPage extends QueryPage { function getSQL() { $dbr =& wfGetDB( DB_SLAVE ); - /* system showing possible actions for users - $user = $dbr->tableName( 'user' ); - $user_rights = $dbr->tableName( 'user_rights' ); - $userspace = Namespace::getUser(); - return "SELECT ur_rights as type, $userspace as namespace, user_name as title, " . - "user_name as value FROM $user LEFT JOIN $user_rights ON user_id = ur_user"; - */ - /** Show groups instead */ $user = $dbr->tableName( 'user' ); $user_groups = $dbr->tableName( 'user_groups' ); $userspace = NS_USER; - $sql = "SELECT CONCAT('Listusers ', ug_group) as type, $userspace AS namespace, user_name AS title, user_name as value " . + $sql = "SELECT 'Listusers' as type, $userspace AS namespace, user_name AS title, ug_group as value " . "FROM $user ". "LEFT JOIN $user_groups ON user_id =ug_user "; if($this->requestedGroup != '') { - $sql .= "WHERE ug_group = '" . IntVal( $this->requestedGroup ) . "' "; + $sql .= 'WHERE ug_group = ' . $dbr->addQuotes( $this->requestedGroup ) . ' '; if($this->requestedUser != '') { $sql .= "AND user_name = " . $dbr->addQuotes( $this->requestedUser ) . ' '; } @@ -138,10 +134,7 @@ class ListUsersPage extends QueryPage { function clearGroups() { $this->concatGroups = ''; } -/* - var $previousResult = false; - var $concatGroups = ''; -*/ + function formatResult( $skin, $result ) { global $wgContLang; $name = false; @@ -155,9 +148,9 @@ class ListUsersPage extends QueryPage { } if( is_object( $result ) && $result->type != '') { - $group = Group::newFromId( intval( strstr( $result->type, ' ' ) ) ); + $group = $result->value; if ( $group ) { - $groupName = $group->getExpandedName(); + $groupName = User::getGroupName( $group ); $this->appendGroups( $skin->makeLink( wfMsgForContent( 'administrators' ), $groupName ) ); } } diff --git a/includes/SpecialPage.php b/includes/SpecialPage.php index 546900100c..4da06a895e 100644 --- a/includes/SpecialPage.php +++ b/includes/SpecialPage.php @@ -72,7 +72,7 @@ $wgSpecialPages = array( 'Lockdb' => new SpecialPage( 'Lockdb', 'siteadmin' ), 'Unlockdb' => new SpecialPage( 'Unlockdb', 'siteadmin' ), 'Userrights' => new SpecialPage( 'Userrights', 'userrights' ), - 'Groups' => new SpecialPage( 'Groups' ), + // 'Groups' => new SpecialPage( 'Groups' ), # currently borken ); global $wgUseValidation ; diff --git a/includes/SpecialStatistics.php b/includes/SpecialStatistics.php index ba4d67876e..bb1793497b 100644 --- a/includes/SpecialStatistics.php +++ b/includes/SpecialStatistics.php @@ -13,7 +13,7 @@ function wfSpecialStatistics() { $fname = 'wfSpecialStatistics'; $dbr =& wfGetDB( DB_SLAVE ); - extract( $dbr->tableNames( 'page', 'site_stats', 'user', 'user_rights' ) ); + extract( $dbr->tableNames( 'page', 'site_stats', 'user', 'user_groups' ) ); $sql = "SELECT COUNT(page_namespace) AS total FROM $page"; $res = $dbr->query( $sql, $fname ); @@ -44,7 +44,7 @@ function wfSpecialStatistics() { $row = $dbr->fetchObject( $res ); $total = $row->total; - $sql = "SELECT COUNT(ur_user) AS total FROM $user_rights WHERE ur_rights LIKE '%sysop%'"; + $sql = "SELECT COUNT(*) AS total FROM $user_groups WHERE ug_group='sysop'"; $res = $dbr->query( $sql, $fname ); $row = $dbr->fetchObject( $res ); $admins = $row->total; diff --git a/includes/SpecialUserrights.php b/includes/SpecialUserrights.php index 6903deb36e..66c6ef1a1e 100644 --- a/includes/SpecialUserrights.php +++ b/includes/SpecialUserrights.php @@ -10,7 +10,6 @@ /** */ require_once('HTMLForm.php'); -require_once('Group.php'); /** Entry point */ function wfSpecialUserrights() { @@ -73,12 +72,12 @@ class UserrightsForm extends HTMLForm { $u = User::newFromName($username); if(is_null($u)) { - $wgOut->addHTML('

    '.wfMsg('nosuchusershort',$username).'

    '); + $wgOut->addWikiText( wfMsg( 'nosuchusershort', htmlspecialchars( $username ) ) ); return; } if($u->getID() == 0) { - $wgOut->addHTML('

    '.wfMsg('nosuchusershort',$username).'

    '); + $wgOut->addWikiText( wfMsg( 'nosuchusershort', htmlspecialchars( $username ) ) ); return; } @@ -93,10 +92,17 @@ class UserrightsForm extends HTMLForm { $newGroups = array_merge($newGroups, $addgroup); } $newGroups = array_unique( $newGroups ); + + wfDebug( 'oldGroups: ' . print_r( $oldGroups, true ) ); + wfDebug( 'newGroups: ' . print_r( $newGroups, true ) ); // save groups in user object and database - $u->setGroups($newGroups); - $u->saveSettings(); + foreach( $removegroup as $group ) { + $u->removeGroup( $group ); + } + foreach( $addgroup as $group ) { + $u->addGroup( $group ); + } $log = new LogPage( 'rights' ); $log->addEntry( 'rights', Title::makeTitle( NS_USER, $u->getName() ), '', array( $this->makeGroupNameList( $oldGroups ), @@ -104,15 +110,7 @@ class UserrightsForm extends HTMLForm { } function makeGroupNameList( $ids ) { - $s = ''; - foreach( $ids as $id ) { - if ( $s != '' ) { - $s .= ', '; - } - $groupObj = Group::newFromId( $id ); - $s .= $groupObj->getExpandedName(); - } - return $s; + return implode( ', ', $ids ); } /** @@ -126,7 +124,10 @@ class UserrightsForm extends HTMLForm { $wgOut->addHTML( "action\" method=\"post\">\n" ); $wgOut->addHTML( $this->fieldset( 'lookup-user', $this->textbox( 'user-editname' ) . - '' + wfElement( 'input', array( + 'type' => 'submit', + 'name' => 'ssearchuser', + 'value' => wfMsg( 'editusergroup' ) ) ) )); $wgOut->addHTML( "
    \n" ); } @@ -139,30 +140,30 @@ class UserrightsForm extends HTMLForm { global $wgOut; $user = User::newFromName($username); - $encUser = htmlspecialchars( $username ); - if(is_null($user)) { - $wgOut->addHTML('

    '.wfMsg('nosuchusershort', $encUser).'

    '); + if( is_null( $user ) || $user->getID() == 0 ) { + $wgOut->addWikiText( wfMsg( 'nosuchusershort', wfEscapeWikiText( $username ) ) ); return; } - - if($user->getID() == 0) { - $wgOut->addHTML('

    '.wfMsg('nosuchusershort', $encUser).'

    '); - return; - } $groups = $user->getGroups(); $wgOut->addHTML( "
    action\" method=\"post\">\n". - ''); - $wgOut->addHTML( $this->fieldset( 'editusergroup', - wfMsg('editing', $this->mRequest->getVal('user-editname')).".
    \n" . + wfElement( 'input', array( + 'type' => 'hidden', + 'name' => 'user-editname', + 'value' => $username ) ) . + $this->fieldset( 'editusergroup', + $wgOut->parse( wfMsg('editing', $username ) ) . '
    '. HTMLSelectGroups('member', $this->mName.'-groupsmember', $groups,true,6). ''. HTMLSelectGroups('available', $this->mName.'-groupsavailable', $groups,true,6,true). '
    '."\n". - '

    '.wfMsg('userrights-groupshelp').'

    '."\n". - '' + $wgOut->parse( wfMsg('userrights-groupshelp') ) . + wfElement( 'input', array( + 'type' => 'submit', + 'name' => 'saveusergroups', + 'value' => wfMsg( 'saveusergroups' ) ) ) )); $wgOut->addHTML( "
    \n" ); } diff --git a/includes/Title.php b/includes/Title.php index 0bc30afc3e..60fc458b72 100644 --- a/includes/Title.php +++ b/includes/Title.php @@ -958,7 +958,7 @@ class Title { /** If anon users can create an account, they need to reach the login page first! */ if( $wgUser->isAllowed( 'createaccount' ) - && $this->mId == NS_SPECIAL + && $this->getNamespace() == NS_SPECIAL && $this->getText() == 'Userlogin' ) { return true; } diff --git a/includes/User.php b/includes/User.php index f029cbc569..103880122c 100644 --- a/includes/User.php +++ b/includes/User.php @@ -9,7 +9,6 @@ * */ require_once( 'WatchedItem.php' ); -require_once( 'Group.php' ); # Number of characters in user_token field define( 'USER_TOKEN_LENGTH', 32 ); @@ -32,9 +31,7 @@ class User { var $mToken; var $mRealName; var $mHash; - /** Array of group id the user belong to */ var $mGroups; - /**#@-*/ /** Construct using User:loadDefaults() */ function User() { @@ -563,7 +560,7 @@ class User { * Load a user from the database */ function loadFromDatabase() { - global $wgCommandLineMode, $wgAnonGroupId, $wgLoggedInGroupId; + global $wgCommandLineMode; $fname = "User::loadFromDatabase"; # Counter-intuitive, breaks various things, use User::setLoaded() if you want to suppress @@ -577,15 +574,9 @@ class User { $this->mId = IntVal( $this->mId ); /** Anonymous user */ - if(!$this->mId) { + if( !$this->mId ) { /** Get rights */ - $anong = Group::newFromId($wgAnonGroupId); - if (!$anong) - wfDebugDieBacktrace("Please update your database schema " - ."and populate initial group data from " - ."maintenance/archives patches"); - $anong->loadFromDatabase(); - $this->mRights = explode(',', $anong->getRights()); + $this->mRights = $this->getGroupPermissions( array( '*' ) ); $this->mDataLoaded = true; return; } # the following stuff is for non-anonymous users only @@ -607,31 +598,16 @@ class User { $this->mTouched = wfTimestamp(TS_MW,$s->user_touched); $this->mToken = $s->user_token; - // Get groups id - $res = $dbr->select( 'user_groups', array( 'ug_group' ), array( 'ug_user' => $this->mId ) ); - - // add the default group for logged in user - $this->mGroups = array( $wgLoggedInGroupId ); - - while($group = $dbr->fetchRow($res)) { - if ( $group[0] != $wgLoggedInGroupId ) { - $this->mGroups[] = $group[0]; - } - } - - - $this->mRights = array(); - // now we merge groups rights to get this user rights - foreach($this->mGroups as $aGroupId) { - $g = Group::newFromId($aGroupId); - $g->loadFromDatabase(); - $this->mRights = array_merge($this->mRights, explode(',', $g->getRights())); + $res = $dbr->select( 'user_groups', + array( 'ug_group' ), + array( 'ug_user' => $this->mId ), + $fname ); + $this->mGroups = array(); + while( $row = $dbr->fetchObject( $res ) ) { + $this->mGroups[] = $row->ug_group; } - - // array merge duplicate rights which are part of several groups - $this->mRights = array_unique($this->mRights); - - $dbr->freeResult($res); + $effectiveGroups = array_merge( array( '*', 'user' ), $this->mGroups ); + $this->mRights = $this->getGroupPermissions( $effectiveGroups ); } $this->mDataLoaded = true; @@ -830,24 +806,75 @@ class User { $this->loadFromDatabase(); return $this->mRights; } - - function addRight( $rname ) { - $this->loadFromDatabase(); - array_push( $this->mRights, $rname ); - $this->invalidateCache(); - } + /** + * Get the list of explicit group memberships this user has. + * The implicit * and user groups are not included. + * @return array of strings + */ function getGroups() { $this->loadFromDatabase(); return $this->mGroups; } - function setGroups($groups) { - $this->loadFromDatabase(); - $this->mGroups = $groups; + /** + * Get the list of implicit group memberships this user has. + * This includes all explicit groups, plus 'user' if logged in + * and '*' for all accounts. + * @return array of strings + */ + function getEffectiveGroups() { + $base = array( '*' ); + if( $this->isLoggedIn() ) { + $base[] = 'user'; + } + return array_merge( $base, $this->getGroups() ); + } + + /** + * Remove the user from the given group. + * This takes immediate effect. + * @string $group + */ + function addGroup( $group ) { + $dbw =& wfGetDB( DB_MASTER ); + $dbw->insert( 'user_groups', + array( + 'ug_user' => $this->getID(), + 'ug_group' => $group, + ), + 'User::addGroup', + array( 'IGNORE' ) ); + + $this->mGroups = array_merge( $this->mGroups, array( $group ) ); + $this->mRights = User::getGroupPermissions( $this->getEffectiveGroups() ); + $this->invalidateCache(); + $this->saveSettings(); + } + + /** + * Remove the user from the given group. + * This takes immediate effect. + * @string $group + */ + function removeGroup( $group ) { + $dbw =& wfGetDB( DB_MASTER ); + $dbw->delete( 'user_groups', + array( + 'ug_user' => $this->getID(), + 'ug_group' => $group, + ), + 'User::removeGroup' ); + + $this->mGroups = array_diff( $this->mGroups, array( $group ) ); + $this->mRights = User::getGroupPermissions( $this->getEffectiveGroups() ); + + $this->invalidateCache(); + $this->saveSettings(); } + /** * A more legible check for non-anonymousness. * Returns true if the user is not an anonymous visitor. @@ -1167,23 +1194,7 @@ class User { 'user_id' => $this->mId ), $fname ); - $dbw->set( 'user_rights', 'ur_rights', implode( ',', $this->mRights ), - 'ur_user='. $this->mId, $fname ); $wgMemc->delete( "$wgDBname:user:id:$this->mId" ); - - // delete old groups - $dbw->delete( 'user_groups', array( 'ug_user' => $this->mId), $fname); - - // save new ones - foreach ($this->mGroups as $group) { - $dbw->replace( 'user_groups', - array(array('ug_user','ug_group')), - array( - 'ug_user' => $this->mId, - 'ug_group' => $group - ), $fname - ); - } } @@ -1226,21 +1237,6 @@ class User { ), $fname ); $this->mId = $dbw->insertId(); - $dbw->insert( 'user_rights', - array( - 'ur_user' => $this->mId, - 'ur_rights' => implode( ',', $this->mRights ) - ), $fname - ); - - foreach ($this->mGroups as $group) { - $dbw->insert( 'user_groups', - array( - 'ug_user' => $this->mId, - 'ug_group' => $group - ), $fname - ); - } } function spreadBlock() { @@ -1591,6 +1587,51 @@ class User { return false; return true; } + + /** + * @param array $groups list of groups + * @return array list of permission key names for given groups combined + * @static + */ + function getGroupPermissions( $groups ) { + global $wgGroupPermissions; + $rights = array(); + foreach( $groups as $group ) { + if( isset( $wgGroupPermissions[$group] ) ) { + $rights = array_merge( $rights, $wgGroupPermissions[$group] ); + } + } + return $rights; + } + + /** + * @param string $group key name + * @return string localized descriptive name, if provided + * @static + */ + function getGroupName( $group ) { + $key = "group-$group-name"; + $name = wfMsg( $key ); + if( $name == '' || $name == "<$key>" ) { + return $group; + } else { + return $name; + } + } + + /** + * Return the set of defined explicit groups. + * The * and 'user' groups are not included. + * @return array + * @static + */ + function getAllGroups() { + global $wgGroupPermissions; + return array_diff( + array_keys( $wgGroupPermissions ), + array( '*', 'user' ) ); + } + } ?> diff --git a/maintenance/archives/patch-user_groups.sql b/maintenance/archives/patch-user_groups.sql new file mode 100644 index 0000000000..50f9999355 --- /dev/null +++ b/maintenance/archives/patch-user_groups.sql @@ -0,0 +1,25 @@ +-- +-- User permissions have been broken out to a separate table; +-- this allows sites with a shared user table to have different +-- permissions assigned to a user in each project. +-- +-- This table replaces the old user_rights field which used a +-- comma-separated blob. +-- +CREATE TABLE /*$wgDBprefix*/user_groups ( + -- Key to user_id + ug_user int(5) unsigned NOT NULL default '0', + + -- Group names are short symbolic string keys. + -- The set of group names is open-ended, though in practice + -- only some predefined ones are likely to be used. + -- + -- At runtime $wgGroupPermissions will associate group keys + -- with particular permissions. A user will have the combined + -- permissions of any group they're explicitly in, plus + -- the implicit '*' and 'user' groups. + ug_group char(16) NOT NULL default '', + + PRIMARY KEY (ug_user,ug_group), + KEY (ug_group) +) TYPE=InnoDB; diff --git a/maintenance/parserTests.php b/maintenance/parserTests.php index e18cb72a68..adb341ba04 100644 --- a/maintenance/parserTests.php +++ b/maintenance/parserTests.php @@ -327,7 +327,7 @@ class ParserTest { 'recentchanges', 'watchlist', 'math', 'searchindex', 'interwiki', 'querycache', - 'objectcache', 'groups' + 'objectcache' ); } @@ -406,13 +406,6 @@ class ParserTest { 'iw_local' => 1 ), ) ); - # Hack: initialize a group - $db->insert( 'groups', array( - 'gr_id' => 1, - 'gr_name' => 'Anonymous', - 'gr_description' => 'Anonymous users', - 'gr_rights' => 'read' ) ); - # Hack: Insert an image to work with $db->insert( 'image', array( 'img_name' => 'Foobar.jpg', diff --git a/maintenance/tables.sql b/maintenance/tables.sql index 37db68bec0..720dc5e11d 100644 --- a/maintenance/tables.sql +++ b/maintenance/tables.sql @@ -114,17 +114,25 @@ CREATE TABLE /*$wgDBprefix*/user ( -- this allows sites with a shared user table to have different -- permissions assigned to a user in each project. -- --- TODO: de-blob this; it should be a property table +-- This table replaces the old user_rights field which used a +-- comma-separated blob. -- -CREATE TABLE /*$wgDBprefix*/user_rights ( +CREATE TABLE /*$wgDBprefix*/user_groups ( -- Key to user_id - ur_user int(5) unsigned NOT NULL, - - -- Comma-separated list of permission keys - ur_rights tinyblob NOT NULL default '', + ug_user int(5) unsigned NOT NULL default '0', - UNIQUE KEY ur_user (ur_user) - + -- Group names are short symbolic string keys. + -- The set of group names is open-ended, though in practice + -- only some predefined ones are likely to be used. + -- + -- At runtime $wgGroupPermissions will associate group keys + -- with particular permissions. A user will have the combined + -- permissions of any group they're explicitly in, plus + -- the implicit '*' and 'user' groups. + ug_group char(16) NOT NULL default '', + + PRIMARY KEY (ug_user,ug_group), + KEY (ug_group) ) TYPE=InnoDB; -- The following table is no longer needed with Enotif >= 2.00 @@ -795,19 +803,11 @@ CREATE TABLE /*$wgDBprefix*/logging ( -- Hold group name and description -CREATE TABLE /*$wgDBprefix*/groups ( - gr_id int(5) unsigned NOT NULL auto_increment, - gr_name varchar(50) NOT NULL default '', - gr_description varchar(255) NOT NULL default '', - gr_rights tinyblob, - PRIMARY KEY (gr_id) - -) TYPE=InnoDB; - --- Relation table between user and groups -CREATE TABLE /*$wgDBprefix*/user_groups ( - ug_user int(5) unsigned NOT NULL default '0', - ug_group int(5) unsigned NOT NULL default '0', - PRIMARY KEY (ug_user,ug_group) - -) TYPE=InnoDB; +--CREATE TABLE /*$wgDBprefix*/groups ( +-- gr_id int(5) unsigned NOT NULL auto_increment, +-- gr_name varchar(50) NOT NULL default '', +-- gr_description varchar(255) NOT NULL default '', +-- gr_rights tinyblob, +-- PRIMARY KEY (gr_id) +-- +--) TYPE=InnoDB; diff --git a/maintenance/updaters.inc b/maintenance/updaters.inc index 735a724f9d..e17cb5c363 100644 --- a/maintenance/updaters.inc +++ b/maintenance/updaters.inc @@ -12,7 +12,7 @@ require_once 'userDupes.inc'; $wgRenamedTables = array( # from to patch file - array( 'group', 'groups', 'patch-rename-group.sql' ), +# array( 'group', 'groups', 'patch-rename-group.sql' ), ); $wgNewTables = array( @@ -22,8 +22,6 @@ $wgNewTables = array( array( 'objectcache', 'patch-objectcache.sql' ), array( 'categorylinks', 'patch-categorylinks.sql' ), array( 'logging', 'patch-logging.sql' ), - array( 'user_rights', 'patch-user_rights.sql' ), - array( 'groups', 'patch-userlevels.sql' ), array( 'validate', 'patch-validate.sql' ), ); @@ -38,8 +36,6 @@ $wgNewFields = array( array( 'user', 'user_real_name', 'patch-user-realname.sql' ), array( 'user', 'user_token', 'patch-user_token.sql' ), array( 'user', 'user_email_token', 'patch-user_email_token.sql' ), - array( 'user_rights', 'ur_user', 'patch-rename-user_groups-and_rights.sql' ), - array( 'groups', 'gr_rights', 'patch-userlevels-rights.sql' ), array( 'logging', 'log_params', 'patch-log_params.sql' ), array( 'archive', 'ar_rev_id', 'patch-archive-rev_id.sql' ), array( 'archive', 'ar_text_id', 'patch-archive-text_id.sql' ), @@ -238,20 +234,6 @@ function do_user_update() { } } -# Assumes that the groups table has been added. -function do_group_update() { - global $wgDatabase; - $res = $wgDatabase->safeQuery( 'SELECT COUNT(*) AS c FROM !', - $wgDatabase->tableName( 'groups' ) ); - $row = $wgDatabase->fetchObject( $res ); - $wgDatabase->freeResult( $res ); - if( $row->c == 0 ) { - echo "Adding default group definitions... "; - dbsource( "maintenance/archives/patch-userlevels-defaultgroups.sql", $wgDatabase ); - echo "ok\n"; - } -} - /** * 1.4 betas were missing the 'binary' marker from logging.log_title, * which causes a collation mismatch error on joins in MySQL 4.1. @@ -572,6 +554,81 @@ function do_user_unique_update() { } } +function do_user_groups_update() { + $fname = 'do_user_groups_update'; + global $wgDatabase; + + if( $wgDatabase->tableExists( 'user_groups' ) ) { + echo "...user_groups table already exists.\n"; + return do_user_groups_reformat(); + } + + echo "Adding user_groups table... "; + dbsource( 'maintenance/archives/patch-user_groups.sql', $wgDatabase ); + echo "ok\n"; + + if( !$wgDatabase->tableExists( 'user_rights' ) ) { + if( $wgDatabase->fieldExists( 'user', 'user_rights' ) ) { + echo "Upgrading from a 1.3 or older database? Breaking out user_rights for conversion..."; + dbsource( 'maintenance/archives/patch-user_rights.sql', $wgDatabase ); + echo "ok\n"; + } else { + echo "*** WARNING: couldn't locate user_rights table or field for upgrade.\n"; + echo "*** You may need to manually configure some sysops by manipulating\n"; + echo "*** the user_groups table.\n"; + return; + } + } + + echo "Converting user_rights table to user_groups... "; + $result = $wgDatabase->select( 'user_rights', + array( 'ur_user', 'ur_rights' ), + array( "ur_rights != ''" ), + $fname ); + + while( $row = $wgDatabase->fetchObject( $result ) ) { + $groups = array_unique( + array_map( 'trim', + explode( ',', $row->ur_rights ) ) ); + + foreach( $groups as $group ) { + $wgDatabase->insert( 'user_groups', + array( + 'ug_user' => $row->ur_user, + 'ug_group' => $group ), + $fname ); + } + } + $wgDatabase->freeResult( $result ); + echo "ok\n"; +} + +function do_user_groups_reformat() { + # Check for bogus formats from previous 1.5 alpha code. + global $wgDatabase; + $info = $wgDatabase->fieldInfo( 'user_groups', 'ug_group' ); + + if( $info->type == 'int' ) { + $oldug = $wgDatabase->tableName( 'user_groups' ); + $newug = $wgDatabase->tableName( 'user_groups_bogus' ); + echo "user_groups is in bogus intermediate format. Renaming to $newug... "; + $wgDatabase->query( "ALTER TABLE $oldug RENAME TO $newug" ); + echo "ok\n"; + + echo "Re-adding fresh user_groups table... "; + dbsource( 'maintenance/archives/patch-user_groups.sql', $wgDatabase ); + echo "ok\n"; + + echo "***\n"; + echo "*** WARNING: You will need to manually fix up user permissions in the user_groups\n"; + echo "*** table. Old 1.5 alpha versions did some pretty funky stuff...\n"; + echo "***\n"; + } else { + echo "...user_groups is in current format.\n"; + } + +} + function do_all_updates() { global $wgNewTables, $wgNewFields, $wgRenamedTables; @@ -592,9 +649,6 @@ function do_all_updates() { flush(); } - # Add default group data - do_group_update(); flush(); - # Do schema updates which require special handling do_interwiki_update(); flush(); do_index_update(); flush(); @@ -615,6 +669,7 @@ function do_all_updates() { do_drop_img_type(); flush(); do_user_unique_update(); flush(); + do_user_groups_update(); flush(); initialiseMessages(); flush(); }